<?php
/**
 * 接口应用类
 * @author tenleaves@gmail.com
 */
class Cms_Apidoc {
	/**
	 * API应用输出的文档格式
	 *
	 * @var String
	 */
	public $apiContentType;
	
	/**
	 * API应用类别,如：website、flex、other……
	 *
	 * @var String
	 */
	public $apiType;
	
	public $apiName;
	
	public $apiDescription;
	
	public $apiVer;
	
	public $response;
	public $responseStatus;
	public $responseErrorCode;
	//	public $techErrMsg;
	//	public $userErrMsg;
	

	public $apiLastBuildDate;
	
	//	public $isDebug;
	//	public $debugParam;
	

	public $doc;
	
	private $simpleXml;
	
	/**
	 * 初始化API基本信息
	 * @param String $api_type
	 * @param String $doc_type
	 */
	function __construct($doc_ver = '1.0', $doc_encode = 'utf8', $api_type = 'oapi') {
		//api基本信息
		$this->apiType = $api_type;
		//		$this->apiVer = $api_ver;
		$this->apiLastBuildDate = date ( "Y-m-d H:i:s", time () );
		
		//api的返回类型，XML或者JSON
		if (isset ( $_GET ['doctype'] ) && $_GET ['doctype'] == 'json') {
			$this->apiContentType = 'json';
		} //默认为XML
else {
			$this->doc = new DOMDocument ( $doc_ver, $doc_encode );
			$this->doc->formatOutput = true;
			$this->apiContentType = 'xml';
			$this->response = $this->doc->createElement ( 'Response' );
		}
		
		if (isset ( $_GET ['debug'] ) && $_GET ['debug']) {
			$this->setDebug ( $_GET, true );
		}
	}
	
	/**
	 * 设置Debug
	function setDebug($param,$debug){
		$this->isDebug = $debug;
		$this->debugParam = $param;
	}
	 */
	
	/**
	 * 设置API名称
	 */
	function setBaseName($name) {
		$this->apiName = $name;
	}
	
	/**
	 * 设置API描述
	 */
	function setBaseDesc($description) {
		$this->apiDescription = $description;
	}
	
	/**
	 * 设置API的错误信息
	 */
	function setErrReStatus($error_msg, $error_code = null) {
		$this->responseStatus = false;
		$this->responseMsg = $error_msg;
		if ($error_code) {
			$this->responseErrorCode = $error_code;
		}
	}
	
	/**
	 * API正常输出
	 */
	function setSucReStatus($suc_msg = '') {
		$this->responseStatus = true;
		$this->responseMsg = $suc_msg;
	}
	
	/**
	 * 生成API
	 */
	function buildAPI() {
		//生成一个XML文件
		if ($this->apiContentType == 'xml') {
			header ( 'Content-Type: text/xml' );
			print_r ( $this->buildXML () );
		} //生成一个JS文件
elseif ($this->apiContentType == 'json') {
			print_r ( $this->buildJSON () );
		}
	}
	
	/**
	 * 构造一个XML数据格式的API
	 */
	private function buildXML() {
		$root = $this->doc->createElement ( 'UQuDe' );
		
		//名称
		$api_name = $this->doc->createElement ( 'Name', $this->apiName );
		$newnode = $root->appendChild ( $api_name );
		
		//用版
		$newnode->setAttribute ( "version", $this->apiVer );
		
		//描述
		$api_description = $this->doc->createElement ( 'Description' );
		$api_description->appendChild ( $this->doc->createCDATASection ( $this->apiDescription ) );
		$root->appendChild ( $api_description );
		
		//最后构造时间
		$latbuild_date = $this->doc->createElement ( 'lastBuildDate', date ( 'Y-m-d H:i:s' ) );
		$root->appendChild ( $latbuild_date );
		
		//设置API返回正确的状态
		if ($this->responseStatus) {
			$response_node = $root->appendChild ( $this->response );
			$response_node->setAttribute ( "status", 'true' );
		} else {
			$this->response = null;
			$this->response = $this->doc->createElement ( 'Response' );
			$response_node = $root->appendChild ( $this->response );
			$response_node->setAttribute ( "status", 'false' );
			
			if ($this->responseErrorCode) {
				$response_errcode_node = $this->doc->createElement ( 'ErrorCode', $this->responseErrorCode );
				$this->response->appendChild ( $response_errcode_node );
			}
		}
		//设置API的返回消息
		$response_msg_node = $this->doc->createElement ( 'Msg' );
		$response_msg_node->appendChild ( $this->doc->createCDATASection ( $this->responseMsg ) );
		$this->response->appendChild ( $response_msg_node );
		
		$this->doc->appendChild ( $root );
		return $this->doc->saveXML ();
	}
	
	/**
	 * 构造一个JSON数据格式的API
	 */
	private function buildJSON() {
		
		$json_rs_arr ['Name'] = $this->apiName;
		$json_rs_arr ['Description'] = $this->apiDescription;
		$json_rs_arr ['lastBuildDate'] = $this->apiLastBuildDate;
		$json_rs_arr ['Response'] = $this->responseResult;
		
		$json_rs_arr ['Response'] ['Msg'] = $this->responseMsg;
		if ($this->responseStatus) {
			$json_rs_arr ['Response'] ['value'] = 'true';
		} else {
			$json_rs_arr ['Response'] ['value'] = 'false';
			if ($this->responseErrorCode) {
				$json_rs_arr ['Response'] ['ErrorCode'] = $this->responseErrorCode;
			}
		}
		//		if($this->isDebug){
		//			$json_rs_arr['Response']['debug']=$this->debugParam;
		//		}
		//dump($json_rs_arr);exit();
		return json_encode ( $json_rs_arr );
	}
	
	/**
	 * 设置API返回的内容
	 * @param mix $result
	 */
	function setResult($result) {
		if (! $result) {
			return null;
		}
		
		if ($this->apiContentType == 'json') {
			$this->responseResult = $result;
		} elseif ($this->apiContentType == 'xml') {
			if (is_array ( $result )) {
				$this->response->appendChild ( $this->_arrayToXML ( $result, 'Resault' ) );
			} else {
				if (is_string ( $result )) {
					$resault_node = $this->doc->createElement ( 'Resault' );
					$resault_node->appendChild ( $this->doc->createCDATASection ( $result ) );
				} elseif (is_integer ( $result )) {
					$resault_node = $this->doc->createElement ( 'Resault', $result );
				}
				$this->response->appendChild ( $resault_node );
			}
		}
		return $this->response;
	}
	/**
	 * 设置API XML 的msg
	 */
	//	function setXmlMsg($result){
	//		$this->xml->xml_add_group('Msg');
	//		$msg_info=$this->xml->xml_build_simple_tag( 'Msg', $result );
	//		return $msg_info;
	//	}
	

	/**
	 * 递归，数组转换为XML
	 *
	 * @param array $array
	 * @param unknown_type $xmlname
	 */
	private function _arrayToXML($array, $xmlname) {
		if (! $array || ! is_array ( $array )) {
			return false;
		}
		$_xml = $this->doc->createElement ( $xmlname );
		foreach ( $array as $key => $val ) {
			if (is_array ( $val )) {
				if (is_numeric ( $key )) {
					$_xml_item = $this->_arrayToXML ( $val, 'item' );
				} else {
					$_xml_item = $this->_arrayToXML ( $val, $key );
				}
			} else {
				$_xml_item = $this->doc->createElement ( $key, $val );
			}
			$_xml->appendChild ( $_xml_item );
		}
		return $_xml;
	}
	
	public function LoadXmlString($xml_string) {
		$this->simpleXml = new SimpleXMLElement ( $xml_string );
		return $this->simpleXml;
	}
	
	public function getXmlNodeAttribute($xml_node, $name) {
		if (get_class ( $xml_node ) != 'SimpleXMLElement') {
			return false;
		}
		foreach ( $xml_node->attributes () as $key => $val ) {
			if ($key == $name) {
				return ( string ) $val;
			}
		}
	}
	
	public function getXmlNodeValue($xml_node) {
		if (get_class ( $xml_node ) != 'SimpleXMLElement') {
			return false;
		}
		if (count ( $xml_node ) > 1) {
			return $xml_node;
		}
		foreach ( $xml_node as $val ) {
			return ( string ) $val;
		}
	}

/**
 * 
//	function setXmlDebug($param){
//		if(is_array($param)){
//			$this->xml->xml_add_group('Debug');
//			foreach($param as $key => $val){
//				if(strtolower($key) == 'debug'){
//					continue;
//				}
//				$debug_xml[] = $this->xml->xml_build_simple_tag( ucwords($key), $val );
//			}
//			$result_xml=$this->xml->xml_build_entry( 'Debug', $debug_xml );
//			return $result_xml;
//		}
//	}
	
 **
 * 返回数组的维数
 */
//	function getArrayDepth($arr){
//		$tmp = serialize($arr);
//		preg_match_all('/\}+/', substr($tmp, 0), $r); 
//		return strlen($r[0][count($r[0])-1]);
//	}
}

class TL_Xml {
	/**
	 * XML header
	 *
	 * @var string
	 */
	var $header = "";
	
	/**
	 * Root tag name
	 *
	 * @var string
	 */
	var $root_tag = '';
	
	/**
	 * Root attributes
	 *
	 * @var string
	 */
	var $root_attributes = "";
	
	/**
	 * Array of entries
	 *
	 * @var array
	 */
	var $entries = array ();
	
	/**
	 * String of compiled XML document
	 *
	 * @var string
	 */
	var $xml_document = "";
	
	/**
	 * Work variable
	 *
	 * @var integer
	 */
	var $depth = 0;
	
	/**
	 * Tmp doc, used during creation
	 *
	 * @var string
	 */
	var $tmp_doc = "";
	
	/**
	 * Tag groups
	 *
	 * @var string
	 */
	var $groups = "";
	
	/**
	 * Index numerically flag
	 *
	 * @var integer
	 */
	var $index_numeric = 0;
	
	/**
	 * Collapse duplicate tags flag
	 *
	 * @var integer
	 */
	var $collapse_dups = 1;
	
	/**
	 * Main XML array of parsed components
	 *
	 * @var array
	 */
	var $xml_array = array ();
	
	/**
	 * Collapse newlines in CDATA tags
	 *
	 * @var integer
	 */
	var $collapse_newlines = 1;
	
	/**
	 * Use lite parser flag
	 *
	 * @var integer
	 */
	var $lite_parser = 0;
	
	/**
	 * DOC type
	 *
	 * @ var string
	 */
	var $doc_type = 'ISO-8859-1';
	
	var $use_doctype = 1;
	
	/*-------------------------------------------------------------------------*/
	// CONSTRUCTOR
	/*-------------------------------------------------------------------------*/
	
	function Model_Xml() {
		//@ini_set("memory_limit", "128M");
	

	//$this->header = '<?xml version="1.0" encoding="'.$this->doc_type.'"?'.'>';
	}
	
	/*-------------------------------------------------------------------------*/
	// Parse an XML document into arrays
	/*-------------------------------------------------------------------------*/
	
	/**
	 * Parse an XML document into an array of field and values
	 *
	 * @param	string	Raw XML Data
	 * @return	void
	 */
	function xml_parse_document($xml) {
		$i = - 1;
		
		//-----------------------------------------
		// Use "lite" parser
		//-----------------------------------------
		

		if ($this->lite_parser) {
			$lite = new xml_lite_parse ();
			
			$lite->xml_parse_it ( $xml );
			
			$this->xml_array = $this->_xml_get_children ( $lite->stack, $i );
			
			//-----------------------------------------
			// Free willy..er..memory
			//-----------------------------------------
			

			$lite->garbage_collect ();
		} //-----------------------------------------
// Use PHP EXPAT Parser?
		//-----------------------------------------
		else {
			if ($this->use_doctype && in_array ( strtolower ( $this->doc_type ), array ('us-ascii', 'utf-8', 'iso-8859-1' ) )) {
				$parser = xml_parser_create ( $this->doc_type );
			} else {
				$parser = xml_parser_create ();
			}
			
			xml_parser_set_option ( $parser, XML_OPTION_CASE_FOLDING, 0 );
			xml_parser_set_option ( $parser, XML_OPTION_SKIP_WHITE, 0 );
			xml_parse_into_struct ( $parser, $xml, $vals );
			xml_parser_free ( $parser );
			
			$this->xml_array = $this->_xml_get_children ( $vals, $i );
		}
		
		//-----------------------------------------
		// Garbage collect
		//-----------------------------------------
		

		unset ( $vals );
		unset ( $xml );
	}
	
	/*-------------------------------------------------------------------------*/
	// Format the XML document
	/*-------------------------------------------------------------------------*/
	
	/**
	 * Parse an array into an XML document
	 *
	 * @param	array	Entry array
	 * @return	void
	 */
	function xml_format_document($entry = array()) {
		$this->header = '<?xml version="1.0" encoding="' . $this->doc_type . '"?' . '>';
		
		$this->xml_document = $this->header ? $this->header . "\n" : '';
		
		$this->xml_document .= "<" . $this->root_tag . $this->root_attributes . ">\n";
		
		$this->xml_document .= $this->tmp_doc;
		
		$this->xml_document .= "\n</" . $this->root_tag . ">";
		
		$this->tmp_doc = "";
	}
	
	/*-------------------------------------------------------------------------*/
	// Set the root tags
	/*-------------------------------------------------------------------------*/
	
	/**
	 * Set the root tag
	 *
	 * @param	string	Root tag name
	 * @param	array	Root tag attributes
	 * @return	void
	 */
	function xml_set_root($tag, $attributes = array()) {
		$this->root_tag = $tag;
		$this->root_attributes = $this->_xml_build_attribute_string ( $attributes );
	}
	
	/*-------------------------------------------------------------------------*/
	// Add entries to the group
	/*-------------------------------------------------------------------------*/
	
	/**
	 * Add entry to XML group
	 *
	 * @param	string	Tag name
	 * @param	array	Entry values
	 * @return	void
	 */
	
	function xml_add_entry_to_group($tag, $entry = array()) {
		$this->tmp_doc .= "\t" . $this->groups [$tag];
		
		if (is_array ( $entry ) and count ( $entry )) {
			foreach ( $entry as $e ) {
				$this->tmp_doc .= "\n\t\t" . $e . "\n";
			}
		}
		
		$this->tmp_doc .= "\t</" . $tag . ">\n";
	}
	
	/*-------------------------------------------------------------------------*/
	// Builds an entry
	/*-------------------------------------------------------------------------*/
	
	/**
	 * Build an XML entry
	 *
	 * @param	string	Tag name
	 * @param	array	Content array
	 * @param	array	Attributes
	 * @return	string
	 */
	
	function xml_build_entry($tag, $content = array(), $attributes = array()) {
		$entry = "<" . $tag . $this->_xml_build_attribute_string ( $attributes ) . ">\n";
		
		if (is_array ( $content ) and count ( $content )) {
			foreach ( $content as $c ) {
				$entry .= "\t\t\t" . $c . "\n";
			}
		}
		
		$entry .= "\t\t</" . $tag . ">";
		
		return $entry;
	}
	
	/*-------------------------------------------------------------------------*/
	// Add a group
	/*-------------------------------------------------------------------------*/
	
	/**
	 * Add a group to an XML document
	 *
	 * @param	string	Tag name
	 * @param	array	Attributes
	 * @return	string
	 */
	function xml_add_group($tag, $attributes = array()) {
		$this->groups [$tag] = "<" . $tag . $this->_xml_build_attribute_string ( $attributes ) . ">";
	}
	
	/*-------------------------------------------------------------------------*/
	// Builds a simple <tag [key="value"]>content</tag> structure
	/*-------------------------------------------------------------------------*/
	
	/**
	 * Build and XML simple tag
	 *
	 * @param	string	Tag name
	 * @param	string	Tag value
	 * @param	array	Attributes
	 * @return	string
	 */
	function xml_build_simple_tag($tag, $description = "", $attributes = array()) {
		return "<" . $tag . $this->_xml_build_attribute_string ( $attributes ) . ">" . $this->_xml_encode_string ( $description ) . "</" . $tag . ">";
	}
	
	/*-------------------------------------------------------------------------*/
	// INTERNAL: Build tree node
	// Adapted from http://eric.pollmann.net/work/public_domain/
	/*-------------------------------------------------------------------------*/
	
	/**
	 * Build tree node
	 *
	 * @param	array	Values
	 * @param	array	Values
	 * @param	string	Counter
	 * @param	string	Tag type
	 * @return	array
	 */
	function _xml_build_tag($thisvals, $vals, &$i, $type) {
		$tag = array ();
		
		if (isset ( $thisvals ['attributes'] )) {
			$tag ['ATTRIBUTES'] = $this->_xml_decode_attribute ( $thisvals ['attributes'] );
		}
		
		if ($type === 'complete') {
			if (isset ( $thisvals ['value'] )) {
				$tag ['VALUE'] = $this->_xml_unconvert_safecdata ( $thisvals ['value'] );
			} else {
				$tag ['VALUE'] = '';
			}
		} else {
			$tag = array_merge ( $tag, $this->_xml_get_children ( $vals, $i ) );
		}
		
		return $tag;
	}
	
	/*-------------------------------------------------------------------------*/
	// INTERNAL: Build a nested array of children
	// Adapted from http://eric.pollmann.net/work/public_domain/
	/*-------------------------------------------------------------------------*/
	
	/**
	 * Build a nested array of children
	 *
	 * @param	array	Values
	 * @param	string	Counter
	 * @return	array
	 */
	
	function _xml_get_children($vals, &$i) {
		$children = array ();
		
		//-----------------------------------
		// CDATA before children
		//-----------------------------------
		

		if ($i > - 1 && isset ( $vals [$i] ['value'] )) {
			$children ['VALUE'] = $this->_xml_unconvert_safecdata ( $vals [$i] ['value'] );
		}
		
		//-----------------------------------
		// Loopy loo
		//-----------------------------------
		

		while ( ++ $i < count ( $vals ) ) {
			$type = $vals [$i] ['type'];
			
			//-----------------------------------
			// CDATA after children
			//-----------------------------------
			

			if ($type === 'cdata') {
				$children ['VALUE'] .= $this->_xml_unconvert_safecdata ( $vals [$i] ['value'] );
			} 

			//-----------------------------------
			// COMPLETE: At end of current branch
			// OPEN:    Node has children, recurse
			//-----------------------------------
			

			else if ($type === 'complete' or $type === 'open') {
				$tag = $this->_xml_build_tag ( $vals [$i], $vals, $i, $type );
				
				if ($this->index_numeric) {
					$tag ['TAG'] = $vals [$i] ['tag'];
					$children [] = $tag;
				} else {
					$children [$vals [$i] ['tag']] [] = $tag;
				}
			} 

			//-----------------------------------
			// End of node?
			//-----------------------------------
			

			else if ($type === 'close') {
				break;
			}
		}
		
		if ($this->collapse_dups) {
			foreach ( $children as $key => $value ) {
				if (is_array ( $value ) && (count ( $value ) == 1)) {
					$children [$key] = $value [0];
				}
			}
		}
		
		return $children;
	}
	
	/*-------------------------------------------------------------------------*/
	// INTERNAL: Builds attribute string
	/*-------------------------------------------------------------------------*/
	
	/**
	 * Builds attribute string
	 *
	 * @param	array	Values
	 * @return	string
	 */
	
	function _xml_build_attribute_string($array = array()) {
		if (is_array ( $array ) and count ( $array )) {
			$string = array ();
			
			foreach ( $array as $k => $v ) {
				$v = trim ( $this->_xml_encode_attribute ( $v ) );
				
				$string [] = $k . '="' . $v . '"';
			}
			
			return ' ' . implode ( " ", $string );
		}
	}
	
	/*-------------------------------------------------------------------------*/
	// INTERNAL: Encodes an attribute string
	/*-------------------------------------------------------------------------*/
	
	/**
	 * Encode XML attribute (Make safe for transport)
	 *
	 * @param	string	Raw data
	 * @return	string	Converted Data
	 */
	function _xml_encode_attribute($t) {
		$t = preg_replace ( "/&(?!#[0-9]+;)/s", '&amp;', $t );
		$t = str_replace ( "<", "&lt;", $t );
		$t = str_replace ( ">", "&gt;", $t );
		$t = str_replace ( '"', "&quot;", $t );
		$t = str_replace ( "'", '&#039;', $t );
		
		return $t;
	}
	
	/*-------------------------------------------------------------------------*/
	// INTERNAL: Encodes an attribute string
	/*-------------------------------------------------------------------------*/
	
	/**
	 * Decode XML attribute (Make safe for transport)
	 *
	 * @param	string	Raw data
	 * @return	string	Converted Data
	 */
	function _xml_decode_attribute($t) {
		$t = str_replace ( "&amp;", "&", $t );
		$t = str_replace ( "&lt;", "<", $t );
		$t = str_replace ( "&gt;", ">", $t );
		$t = str_replace ( "&quot;", '"', $t );
		$t = str_replace ( "&#039;", "'", $t );
		
		return $t;
	}
	
	/*-------------------------------------------------------------------------*/
	// INTERNAL: Encodes a string to make it safe (uses cdata)
	/*-------------------------------------------------------------------------*/
	
	/**
	 * Encode XML attribute (Make safe for transport)
	 *
	 * @param	string	Raw data
	 * @return	string	Converted Data
	 */
	
	function _xml_encode_string($v) {
		if (preg_match ( "/['\"\[\]<>&]/", $v )) {
			$v = "<![CDATA[" . $this->_xml_convert_safecdata ( $v ) . "]]>";
		}
		
		if ($this->collapse_newlines) {
			$v = str_replace ( "\r\n", "\n", $v );
		}
		
		return $v;
	}
	
	/*-------------------------------------------------------------------------*/
	// INTERNAL: Ensures no embedding of cdata
	/*-------------------------------------------------------------------------*/
	
	/**
	 * Encode CDATA XML attribute (Make safe for transport)
	 *
	 * @param	string	Raw data
	 * @return	string	Converted Data
	 */
	
	function _xml_convert_safecdata($v) {
		# Legacy
		//$v = str_replace( "<![CDATA[", "<!CDATA|", $v );
		//$v = str_replace( "]]>"      , "|>"      , $v );
		

		# New
		$v = str_replace ( "<![CDATA[", "<!#^#|CDATA|", $v );
		$v = str_replace ( "]]>", "|#^#]>", $v );
		
		return $v;
	}
	
	/*-------------------------------------------------------------------------*/
	// INTERNAL: Uncoverts safe embedding
	/*-------------------------------------------------------------------------*/
	
	/**
	 * Decode CDATA XML attribute (Make safe for transport)
	 *
	 * @param	string	Raw data
	 * @return	string	Converted Data
	 */
	
	function _xml_unconvert_safecdata($v) {
		# Legacy
		$v = str_replace ( "<!CDATA|", "<![CDATA[", $v );
		$v = str_replace ( "|>", "]]>", $v );
		
		# New
		$v = str_replace ( "<!#^#|CDATA|", "<![CDATA[", $v );
		$v = str_replace ( "|#^#]>", "]]>", $v );
		
		return $v;
	}
	/**
	 * 将数据转成RSS格式
	 *
	 * @param array() $a_rss_info			以标签名称为键的频道信息数组 
	 * @param array() $a_content			以标签名称为键的显示数据的信息数组
	 * @return unknown
	 * ex.
	 * $xml = &get_singleton('Model_Xml');
	 * $a_info	= array('title' => '标题' , 'link' => '链接');
	 * $a_data	= array(array('title' => '标题1', 'link'=>'链接1'),array('title' => '标题2', 'link'=>'链接2'));
	 * $xml->xml_array_to_rss($a_info,$a_data);
	 * 
	 */
	function xml_array_to_rss($a_rss_info = array(), $a_content = array()) {
		$this->doc_type = 'UTF-8';
		$this->xml_set_root ( 'rss', array ('version' => '2.0' ) );
		//		xml信息
		$this->xml_add_group ( 'channel' );
		//频道信息
		$entry [] = $this->xml_build_entry ( 'title', array ($a_rss_info ['title'] ) );
		$entry [] = $this->xml_build_entry ( 'link', array ($a_rss_info ['link'] ) );
		$entry [] = $this->xml_build_entry ( 'description', array ($a_rss_info ['description'] ) );
		$entry [] = $this->xml_build_entry ( 'copyright', array ("Copyright(C) {$a_rss_info['copyright']}" ) );
		$entry [] = $this->xml_build_entry ( 'lastBuildDate', array ($a_rss_info ['lastBuildDate'] ) );
		$entry [] = $this->xml_build_entry ( 'ttl', array ($a_rss_info ['ttl'] ) );
		//频道图片信息
		$img [] = $this->xml_build_simple_tag ( 'title', $a_rss_info ['img'] ['title'] );
		$img [] = $this->xml_build_simple_tag ( 'url', $a_rss_info ['img'] ['url'] );
		$img [] = $this->xml_build_simple_tag ( 'link', $a_rss_info ['img'] ['link'] );
		$entry [] = $this->xml_build_entry ( 'image', $img );
		//频道项信息
		foreach ( $a_content as $key => $value ) {
			$item [$key] [] = $this->xml_build_simple_tag ( 'title', $value ['title'] );
			$item [$key] [] = $this->xml_build_simple_tag ( 'link', $value ['link'] );
			$item [$key] [] = $this->xml_build_simple_tag ( 'description', $value ['description'] );
			$item [$key] [] = $this->xml_build_simple_tag ( 'category', $value ['category'] );
			$item [$key] [] = $this->xml_build_simple_tag ( 'author', $value ['author'] );
			$item [$key] [] = $this->xml_build_simple_tag ( 'pubDate', $value ['pubDate'] );
			
			$entry [] = $this->xml_build_entry ( 'item', $item [$key] );
		}
		
		$this->xml_add_entry_to_group ( 'channel', $entry );
		$this->xml_format_document ();
		$filecontents = auto2utf8 ( $this->xml_document );
		//		$filecontents = iconv("GBK","UTF-8",$this->xml_document);
		return $filecontents;
	}

}

//======================================================================================
// CLASS: XML_LITE_PARSE (Takes parsed XML and puts into EXPAT compatible array
//======================================================================================


/**
 * XML-LITE Extraction
 *
 * Methods and functions for handling XML documents
 *
 * @package	IPS_KERNEL
 * @subpackage	XMLHandling
 * @author   Matt Mecham
 * @version	2.1
 */
class xml_lite_parse {
	var $xml_class;
	var $parser;
	var $preserve_cdata = 1;
	var $stack = array ();
	var $level = 1;
	var $tagname = "";
	var $array_id = 0;
	var $last_id = 0;
	var $tagopen = array ();
	var $xmldoc = "";
	
	/*-------------------------------------------------------------------------*/
	// CONSTRUCTOR
	/*-------------------------------------------------------------------------*/
	
	function xml_lite_parse() {
	
	}
	
	/*-------------------------------------------------------------------------*/
	// Main parser
	/*-------------------------------------------------------------------------*/
	
	function xml_parse_it($xmldoc) {
		$parser = new xml_extract ();
		
		$this->xmldoc = $xmldoc;
		
		unset ( $xmldoc );
		
		//-----------------------------------------
		// Set up element handlers
		//-----------------------------------------
		

		$parser->my_xml_set_element_handler ( array (&$this, 'my_start_element' ), array (&$this, 'my_end_element' ) );
		$parser->my_xml_set_character_data_handler ( array (&$this, 'my_data_element' ) );
		
		if ($this->preserve_cdata) {
			$parser->my_xml_set_cdata_section_handler ( array (&$this, 'my_cdata_element' ) );
		}
		
		$parser->xml_parse_document ( $this->xmldoc );
	}
	
	/*-------------------------------------------------------------------------*/
	// Start element
	/*-------------------------------------------------------------------------*/
	
	function my_start_element(&$parser_obj, $name, $attr) {
		//-------------------------------
		// Add to stack
		//-------------------------------
		

		$this->stack [$this->array_id] = array ('tag' => $name, 'type' => 'open', 'level' => $this->level, 'value' => '' );
		
		//-------------------------------
		// Attributes?
		//-------------------------------
		

		if (is_array ( $attr ) and count ( $attr )) {
			$this->stack [$this->array_id] ['attributes'] = $attr;
		}
		
		//-------------------------------
		// Flying higher than an eagle?
		//-------------------------------
		

		if ($this->tagname != $name) {
			if ($this->tagopen [$name]) {
				$this->level = $this->tagopen [$name];
			} else {
				$this->level ++;
			}
		}
		
		//-------------------------------
		// Set current tag name
		//-------------------------------
		

		$this->tagname = $name;
		
		//-------------------------------
		// Inc. array ID
		//-------------------------------
		

		$this->array_id ++;
		
		//-------------------------------
		// Set tag == depth
		//-------------------------------
		

		$this->tagopen [$name] = $this->level;
	}
	
	/*-------------------------------------------------------------------------*/
	// Start element
	/*-------------------------------------------------------------------------*/
	
	function my_end_element(&$parser_obj, $name) {
		$this->stack [$this->array_id] = array ('tag' => $name, 'type' => 'close', 'level' => $this->tagopen [$name] - 1 );
		
		//-------------------------------
		// Update already done data?
		//-------------------------------
		

		if (($this->stack [$this->array_id - 2] ['tag'] == $this->tagname) and ($this->stack [$this->array_id - 1] ['_data'] == 1)) {
			//-------------------------------
			// Update previous tag
			//-------------------------------
			

			$this->stack [$this->array_id - 2] ['value'] = class_xml::_xml_unconvert_safecdata ( $this->stack [$this->array_id - 1] ['value'] );
			$this->stack [$this->array_id - 2] ['type'] = 'complete';
			
			unset ( $this->stack [$this->array_id - 1] );
			unset ( $this->stack [$this->array_id] );
			
			$this->array_id -= 2;
			$this->last_id = $this->array_id - 1;
		}
		
		$this->tagname = "";
		
		$this->array_id ++;
		$this->level --;
	}
	
	/*-------------------------------------------------------------------------*/
	// DATA element
	/*-------------------------------------------------------------------------*/
	
	function my_data_element(&$parser_obj, $data) {
		if ($this->tagname) {
			$this->stack [$this->array_id] = array ('tag' => $this->tagname, 'type' => 'open', 'level' => $this->level, 'value' => class_xml::_xml_unconvert_safecdata ( $data ), '_data' => 1 );
		}
		
		//-------------------------------
		// Inc. array ID
		//-------------------------------
		

		$this->array_id ++;
	}
	
	/*-------------------------------------------------------------------------*/
	// CDATA element
	/*-------------------------------------------------------------------------*/
	
	function my_cdata_element(&$parser_obj, $data) {
		$this->my_data_element ( $parser_obj, $data );
	}
	
	/*-------------------------------------------------------------------------*/
	// Free memory
	/*-------------------------------------------------------------------------*/
	
	function garbage_collect() {
		$this->stack = array ();
		$this->tagname = array ();
		$this->array_id = 0;
		$this->level = 0;
		$this->xmldoc = "";
	}

}

//======================================================================================
// CLASS: XML_EXTRACT (Parses XML file)
//======================================================================================


/**
 * XML-LITE Extraction Sub class
 *
 * Methods and functions for handling XML documents
 *
 * @package	IPS_KERNEL
 * @subpackage	XMLHandling
 * @author   Matt Mecham
 * @version	2.1
 */
class xml_extract {
	var $xml_array = array ();
	var $chr_sofar = "";
	var $handler_cdata_handler;
	var $handler_character_data;
	var $handler_end_element;
	var $handler_start_element;
	
	//-----------------------------------------
	// Definitions
	//-----------------------------------------
	

	var $xml_constants = array ('CDATA_TAG' => '![CDATA[', 'CDATA_LEN' => 8, 'NOTATION' => '!NOTATION', 'DOCTYPE' => '!DOCTYPE' );
	
	/*-------------------------------------------------------------------------*/
	// CONSTRUCTOR
	/*-------------------------------------------------------------------------*/
	
	function xml_extract() {
	
	}
	
	/*-------------------------------------------------------------------------*/
	// MAIN "PARSE" ROUTINE (Roughly mime EXPAT in PHP)
	/*-------------------------------------------------------------------------*/
	
	function xml_parse_document($xml) {
		//-----------------------------------------
		// Grab all relevant XML data
		// Strip off header, DOC TYPE, etc
		//-----------------------------------------
		

		$xml = preg_replace ( "#^(?:.*?)?(<.*>)(?:.*?)?$#s", "\\1", $xml );
		
		$xml_strlen = strlen ( $xml );
		
		//-----------------------------------------
		// Pick through, char by char
		//-----------------------------------------
		

		for($i = 0; $i < $xml_strlen; $i ++) {
			$chr = $xml {$i};
			
			switch ($chr) {
				case '<' :
					if (substr ( $this->chr_sofar, 0, $this->xml_constants ['CDATA_LEN'] ) == $this->xml_constants ['CDATA_TAG']) {
						//-----------------------------------------
						// Processing CDATA
						//-----------------------------------------
						

						$this->chr_sofar .= $chr;
					} else {
						$this->parse_between_tags ( $this->chr_sofar );
						$this->chr_sofar = '';
					}
					break;
				case '>' :
					if ((substr ( $this->chr_sofar, 0, $this->xml_constants ['CDATA_LEN'] ) == $this->xml_constants ['CDATA_TAG']) and ! (($this->_get_nth_char_from_end ( $this->chr_sofar, 0 ) == ']') and ($this->_get_nth_char_from_end ( $this->chr_sofar, 1 ) == ']'))) {
						$this->chr_sofar .= $chr;
					} else {
						if ($xml {strlen ( $this->chr_sofar + 1 )} == ']') {
							$this->chr_sofar .= $chr;
						} else {
							$this->parse_tag ( $this->chr_sofar );
							$this->chr_sofar = '';
						}
					}
					break;
				default :
					$this->chr_sofar .= $chr;
			}
		}
		
		unset ( $xml );
	}
	
	/*-------------------------------------------------------------------------*/
	// Parse tag
	/*-------------------------------------------------------------------------*/
	
	function parse_tag($text) {
		$attr = array ();
		$text = trim ( $text );
		$fchr = $text {0};
		
		switch ($fchr) {
			//-----------------------------------------
			// First char is closing tag?
			//-----------------------------------------
			case '/' :
				
				$tag_name = substr ( $text, 1 );
				$this->exec_end_element ( $tag_name );
				break;
			//-----------------------------------------
			// First char is instruction/doctype?
			//-----------------------------------------
			case '!' :
				
				$uc_tag_text = strtoupper ( $text );
				
				if (strpos ( $uc_tag_text, $this->xml_constants ['CDATA_TAG'] ) !== false) {
					//-----------------------------------------
					// CDATA text
					//-----------------------------------------
					

					$total = strlen ( $text );
					$openbrace_cnt = 0;
					$tn_text = '';
					
					for($i = 0; $i < $total; $i ++) {
						$cc = $text {$i};
						
						//-----------------------------------------
						// End of CDATA?
						//-----------------------------------------
						

						if (($cc == ']') && ($text {($i + 1)} == ']')) {
							if (! $text {($i + 2)} == ']') {
								break;
							} else {
								$tn_text .= $cc;
							}
						} else if ($openbrace_cnt > 1) {
							$tn_text .= $cc;
						} else if ($cc == '[') {
							//-----------------------------------------
							// Won't get here until first OB reached
							//-----------------------------------------
							

							$openbrace_cnt ++;
						}
					}
					
					if ($this->handler_cdata_handler == null) {
						$this->exec_character_data ( $tn_text );
					} else {
						$this->exec_cdata_element ( $tn_text );
					}
				} else if (strpos ( $uc_tag_text, $this->xml_constants ['NOTATION'] ) !== false) {
					//-----------------------------------------
					// !NOTATION? Ignore!
					//-----------------------------------------
					

					return;
				} else if (substr ( $text, 0, 2 ) == '!-') {
					//-----------------------------------------
					// !Comment? Ignore!
					//-----------------------------------------
					

					return;
				}
				
				break;
			//-----------------------------------------
			// Case is ?INSTRUCTION?
			//-----------------------------------------
			case '?' :
				
				//-----------------------------------------
				// Instruction? Ignore!
				//-----------------------------------------
				

				return;
			//-----------------------------------------
			// Normal tag - woohoo!
			//-----------------------------------------
			default :
				
				if ((strpos ( $text, '"' ) !== false) || (strpos ( $text, "'" ) !== false)) {
					$total = strlen ( $text );
					$tag_name = '';
					
					for($i = 0; $i < $total; $i ++) {
						$cc = $text {$i};
						
						if ($cc == ' ') {
							$attr = $this->parse_attr ( substr ( $text, $i ) );
							break;
						} else {
							$tag_name .= $cc;
						}
					}
					
					if (strrpos ( $text, '/' ) == (strlen ( $text ) - 1)) {
						$this->exec_start_element ( $tag_name, $attr );
						$this->exec_end_element ( $tag_name );
					} else {
						$this->exec_start_element ( $tag_name, $attr );
					}
				} else {
					if (strpos ( $text, '/' ) !== false) {
						$text = trim ( substr ( $text, 0, (strrchr ( $text, '/' ) - 1) ) );
						$this->exec_start_element ( $text, $attr );
						$this->exec_end_element ( $text );
					} else {
						$this->exec_start_element ( $text, $attr );
					}
				}
		}
	}
	
	/*-------------------------------------------------------------------------*/
	// Parse Attributes
	/*-------------------------------------------------------------------------*/
	
	function parse_attr($text) {
		$text = trim ( $text );
		$attr_array = array ();
		$query_entity = false;
		
		$total = strlen ( $text );
		$dump_key = '';
		$dump_value = '';
		$cur_state = 0; // 0 = none, 1 = key, 2 = value
		$quote_type = '';
		
		for($i = 0; $i < $total; $i ++) {
			$cc = $text {$i};
			
			if ($cur_state == 0) {
				if (trim ( $cc != '' )) {
					$cur_state = 1;
				}
			}
			
			switch ($cc) {
				//-----------------------------------------
				// Tab and we're in a value?
				//-----------------------------------------
				case "\t" :
					if ($cur_state == 2) {
						$dump_value .= $cc;
					} else {
						$cc = '';
					}
					break;
				//-----------------------------------------
				// Newlines..
				//-----------------------------------------
				case "\n" :
				case "\r" :
					$cc = '';
					break;
				//-----------------------------------------
				// Param value
				//-----------------------------------------
				case '=' :
					if ($cur_state == 2) {
						$dump_value .= $cc;
					} else {
						$cur_state = 2;
						$quote_type = '';
						$query_entity = false;
					}
					break;
				//-----------------------------------------
				// Quoted
				//-----------------------------------------
				case '"' :
					if ($cur_state == 2) {
						if ($quote_type == '') {
							$quote_type = '"';
						} else {
							if ($quote_type == $cc) {
								$attr_array [trim ( $dump_key )] = trim ( $dump_value );
								$dump_key = $dump_value = $quote_type = '';
								$cur_state = 0;
							} else {
								$dump_value .= $cc;
							}
						}
					}
					break;
				//-----------------------------------------
				// Quoted
				//-----------------------------------------
				case "'" :
					if ($cur_state == 2) {
						if ($quote_type == '') {
							$quote_type = "'";
						} else {
							if ($quote_type == $cc) {
								$attr_array [trim ( $dump_key )] = trim ( $dump_value );
								$dump_key = $dump_value = $quote_type = '';
								$cur_state = 0;
							} else {
								$dump_value .= $cc;
							}
						}
					}
					break;
				//-----------------------------------------
				// Entity?
				//-----------------------------------------
				case '&' :
					$query_entity = true;
					$dump_value .= $cc;
					break;
				
				default :
					if ($cur_state == 1) {
						$dump_key .= $cc;
					} else {
						$dump_value .= $cc;
					}
			}
		}
		
		return $attr_array;
	}
	
	/*-------------------------------------------------------------------------*/
	// Parse between the element tags
	/*-------------------------------------------------------------------------*/
	
	function parse_between_tags($t) {
		if (trim ( $t ) != '') {
			$this->exec_character_data ( $t );
		}
	}
	
	/*-------------------------------------------------------------------------*/
	// Exec_events
	/*-------------------------------------------------------------------------*/
	
	function exec_character_data($data) {
		call_user_func ( $this->handler_character_data, $this, $data );
	}
	
	function exec_start_element($tagname, $attr) {
		call_user_func ( $this->handler_start_element, $this, $tagname, $attr );
	}
	
	function exec_end_element($tagname) {
		call_user_func ( $this->handler_end_element, $this, $tagname );
	}
	
	function exec_cdata_element($data) {
		call_user_func ( $this->handler_cdata_handler, $this, $data );
	}
	
	/*-------------------------------------------------------------------------*/
	// Set xml element handlers
	/*-------------------------------------------------------------------------*/
	
	function my_xml_set_element_handler($startHandler, $endHandler) {
		$this->handler_start_element = $startHandler;
		$this->handler_end_element = $endHandler;
	}
	
	function my_xml_set_character_data_handler($handler) {
		$this->handler_character_data = &$handler;
	}
	
	function my_xml_set_cdata_section_handler($handler) {
		$this->handler_cdata_handler = &$handler;
	}
	
	/*-------------------------------------------------------------------------*/
	// Internal: Get nth character of $text
	/*-------------------------------------------------------------------------*/
	
	function _get_nth_char_from_end($t, $i) {
		return $t {(strlen ( $t ) - 1 - $i)};
	}
}
